﻿using cubeworld.World;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace cubeworld
{
    class Camera
    {
        public bool Frezze = true;
        bool _jumpAllowed = true;
        bool _jumping;
        public Vector3 LookAt;
        public int MouseInvert = -1;

        bool _mouseRotate;
        bool _move;
        float _moveSpeed;

        KeyboardState _oldState;
        int _oldX, _oldY;
        public float Pitch;
        Vector3 _position;
        Matrix _projection;
        float _rotateSpeed;
        Matrix _rotationMatrix;

        Vector3 _start = Vector3.Zero;
        public Matrix View;
        public float Yaw;

        public Camera(Vector3 position, Vector3 dir, float renderDistance)
        {
            this._position = position;
            LookAt = dir;
            SetUpView(position, dir);
            SetUpProjection(renderDistance);
        }

        public Vector3 Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public Matrix Projection
        {
            get { return _projection; }
            set { _projection = value; }
        }

        void SetUpView(Vector3 position, Vector3 dir)
        {
            View = Matrix.CreateLookAt(position, dir, Vector3.Up);
        }

        void SetUpProjection(float renderDistance)
        {
            _projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, MainGame.Device.Viewport.AspectRatio,
                                                             0.1f, renderDistance);
        }

        public void SetUpMovement(bool move, bool mouseRotate, float moveSpeed, float rotateSpeed)
        {
            this._move = move;
            this._mouseRotate = mouseRotate;

            this._moveSpeed = moveSpeed;
            this._rotateSpeed = rotateSpeed;
        }

        public void Update()
        {
            if (Frezze == false)
            {
                if (_move)
                {
                    KeyboardState keyState = Keyboard.GetState();

                    if (keyState.IsKeyDown(Keys.W))
                    {
                        Vector3 v = Vector3.Forward*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.S))
                    {
                        Vector3 v = Vector3.Backward*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);


                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.D))
                    {
                        Vector3 v = Vector3.Right*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.A))
                    {
                        Vector3 v = Vector3.Left*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.E))
                    {
                        Vector3 v = Vector3.Up*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.Q))
                    {
                        Vector3 v = Vector3.Down*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

#if DEBUG
                    if (keyState.IsKeyDown(Keys.E))
                    {
                        Vector3 v = Vector3.Up*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }

                    if (keyState.IsKeyDown(Keys.Q))
                    {
                        Vector3 v = Vector3.Down*_moveSpeed;

                        Matrix forwardMovement = Matrix.CreateRotationY(Yaw);
                        v = Vector3.Transform(v, forwardMovement);

                        _position = Collision.TryMove(v, _position, Data.world.giveCurrentChunkBlocks());
                    }
#endif


                    if (!_jumping)
                    {
#if !DEBUG
                        Vector3 v2 = Vector3.Down * moveSpeed * 5;

                        Matrix forwardMovement2 = Matrix.CreateRotationY(yaw);
                        v2 = Vector3.Transform(v2, forwardMovement2);

                        position = World.Collision.tryMove(v2, position, out jumpAllowed, Data.world.giveCurrentChunkBlocks());
                        jumpAllowed = !jumpAllowed;
#endif
                    }

                    if (_jumping)
                    {
                        if (_jumpAllowed)
                        {
                            _jumpAllowed = false;
                            _start = _position;
                        }

                        Vector3 v2 = Vector3.Up*0.1f;

                        Matrix forwardMovement2 = Matrix.CreateRotationY(Yaw);
                        v2 = Vector3.Transform(v2, forwardMovement2);

                        _position = Collision.TryMove(v2, _position, out _jumping, Data.world.giveCurrentChunkBlocks());


                        if ((_position.Y - _start.Y) > 1.5f)
                        {
                            _jumping = false;
                        }
                    }
                    else if (!_jumping && _jumpAllowed && Keyboard.GetState().IsKeyDown(Keys.Space) &&
                             _oldState.IsKeyUp(Keys.Space))
                    {
                        _jumping = true;
                        _jumpAllowed = true;
                    }
                }

                if (_mouseRotate)
                {
                    MouseState mouse = Mouse.GetState();

                    int dx = mouse.X - _oldX;
                    Yaw -= _rotateSpeed*dx;
                    int dy = mouse.Y - _oldY;
                    Pitch -= _rotateSpeed*dy;

                    if (Pitch > 1.5f)
                        Pitch = 1.5f;
                    if (Pitch < -1.5f)
                        Pitch = -1.5f;

                    MainGame.Win.Title = "YAW: " + Yaw + "   PITCH: " + Pitch;

                    ResetCursor();
                }

                _oldState = Keyboard.GetState();


                UpdateMatrices();
            }
        }

        void ResetCursor()
        {
            Mouse.SetPosition(MainGame.Device.Viewport.Width/2, MainGame.Device.Viewport.Height/2);
            _oldX = MainGame.Device.Viewport.Width/2;
            _oldY = MainGame.Device.Viewport.Height/2;
        }

        void UpdateMatrices()
        {
            _rotationMatrix = Matrix.CreateFromYawPitchRoll(Yaw, Pitch, 0);
            Vector3 transReference = Vector3.Transform(Vector3.Forward, _rotationMatrix);
            Vector3 lookAt = _position + transReference;

            View = Matrix.CreateLookAt(_position, lookAt, Vector3.Up);
        }
    }
}